package engine;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import javax.swing.SwingWorker;
import model_booleen.*;
import ui.UserInterface;

public class SimilarityCalculatorOptimized extends SwingWorker<ArrayList<ResultEntry>, Integer> {

    public static enum SimilarityModel {

        VECTORIEL, BOOL_ETENDU, BOOL_SIMPLE
    };
    private SimilarityCalculator.SimilarityModel model;
    private String request;
    private String rootPath;
    private ArrayList<ResultEntry> results;
    private IndexReader indexReader;
    private UserInterface guiToUpdate;
    private HashMap<String, Double> requestWeights;

    public SimilarityCalculatorOptimized(SimilarityCalculator.SimilarityModel model,
            String request,
            String rootPath,
            IndexReader indexReader) {

        this.model = model;
        this.request = request;
        this.rootPath = rootPath;
        this.indexReader = indexReader;

        this.requestWeights = null;

    }

    public HashMap<String, Double> getRequestWeights() {
        return requestWeights;
    }

    public void setRequestWeights(HashMap<String, Double> requestWeights) {
        this.requestWeights = requestWeights;
    }

    public double modeleVectoriel(HashMap<String, Double> weightsDoc1, HashMap<String, Double> weightsDoc2) {
        //System.out.println("AA");
        Double result = 0.;

        Double wR, wQ;
        Double sumR = 0., sumQ = 0.;
        for (Map.Entry<String, Double> entry : weightsDoc1.entrySet()) {
            wR = entry.getValue();
            wQ = weightsDoc2.get(entry.getKey());
//            if(wR > 0.) System.out.println("Ne dois pas arriver1.");
//            if(wQ > 0.) System.out.println("Ne dois pas arriver2.");
            sumR += wR;
            sumQ += wQ;

            result += wR * wQ;
        }

        if ((sumR * sumQ) == 0.) {
            System.out.println("Ne dois pas arriver.");
        }

        //result = (sumR * sumQ == 0.) ? 0. : result / (sumR * sumQ);

        //ystem.out.println("result" + result);
        return result;
    }

    public double modeleBoolSimple(String request, HashMap<String, Double> weightsDoc) {
        RechercheBooleanSimple.buildQuery(request);
        return RechercheBooleanSimple.calculus(weightsDoc);
    }

    public double modeleBoolEtendu(String request, HashMap<String, Double> weightsDoc) {
        RegleRecherche.buildQuery(request);
        return RegleRecherche.calculus(weightsDoc);
    }

    @Override
    protected ArrayList<ResultEntry> doInBackground() throws Exception {
        results = new ArrayList<ResultEntry>();

        int compteur = 0, progress;
        double score = 0;

        publish(1);//1%

        //Récupérer le vocabulaire
        ArrayList<String> voc = this.indexReader.getVocabulary();

        HashMap<String, Double> curWeights;

        if (requestWeights == null) {
            requestWeights = indexReader.makeVectorFromRequest(request);
        } else {
            System.out.println("Better request found");
        }
        
        String[] line;
        String[] values;
        String currentDocumentFilePath;
        ArrayList<Double> currentVector;
        
        //Pour chaque vecteur TfIdf
        try (Scanner scanner = new Scanner(Paths.get(indexReader.getTfIdfPath()))) {
            while (scanner.hasNextLine()) {
                line = scanner.nextLine().split(":");
                values = line[1].split(";");
                currentVector = new ArrayList<Double>();
                for (String v : values) {
                    currentVector.add(Double.parseDouble(v));
                }
                
                currentDocumentFilePath = indexReader.getDocPath(line[0]);
                
                //Créer la hashmap<mot, poids>
                curWeights = new HashMap<String, Double>();

                for (int i = 0; i < currentVector.size(); i++) {
                    curWeights.put(voc.get(i), currentVector.get(i));
                }

                switch (model) {
                    case VECTORIEL:
                        score = modeleVectoriel(requestWeights, curWeights);
                        break;
                    case BOOL_ETENDU:
                        score = modeleBoolEtendu(this.request, curWeights);
                        break;
                    case BOOL_SIMPLE:
                        score = modeleBoolSimple(this.request, curWeights);
                        break;
                }

                ResultEntry curRes = new ResultEntry(currentDocumentFilePath, score, this.rootPath);;
                results.add(curRes);
                compteur++;
                System.out.println("Calc vecteur : " + compteur);
                progress = (int) ((double) compteur * 100 / 119);
                publish(progress);
            }

        }
        publish(100);
        
        return results;
    }

    @Override
    protected void process(List<Integer> values) {
        for (Integer val : values) {
            guiToUpdate.updateBarCalcSimi(val);
        }
    }

    @Override
    protected void done() {
        guiToUpdate.similarityCalculated();
    }

    public void setGuiToUpdate(UserInterface guiToUpdate) {
        this.guiToUpdate = guiToUpdate;
    }
}
